%%%%%%%%%%%%%%%%%%%%%%%
%%
%% Module summary
%%
%% Main authors: Peter
%% Progress to usefulness: 
%%
%% Simple database backend, stores values
%% in memory using a dict.
%%
%% External function calls:
%% 
%% {put, Key, Value} -- Store 'Key' and 'Value' at correct node
%% {get, Key}        -- Get value from node holding 'Key'
%%
%%%%%%%%%%%%%%%%%%%%%%%
-module(dict_backend).
-behaviour(gen_server).
-include("db.hrl").

% gen_server API
-export([start_link/0,start_link/1]).

% gen_server API
-export([init/1, handle_call/3,handle_cast/2,handle_info/2
        ,terminate/2, code_change/3]).


start_link() ->
    io:format("Using dict backend\n"),
    gen_server:start_link({local,backend},dict_backend,[],[]).

start_link(Args) ->
    io:format("Using dict backend\n"),
    gen_server:start_link({local,backend},dict_backend,Args,[]).

% Initial dictionary
% should return {ok, State}
init(State) ->
    {ok, new_state(State)}.

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
%   Internal "function calls"
%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

%
% Handle put
%
handle_call({put, Key, Value}, _From, State) ->
    NewState = add_value(Key, Value, State),
    case State#dict.verbose of
        true  ->
            io:format("Inserting: (~p,~p)~n",[Key,Value]);
        false -> ok
    end,
    {reply,{ok,put}, NewState};
%
% Handle get
%
handle_call({get, Key}, _From, State) ->
    Value = get_value(Key, State),
    {reply, Value, State};
%
% This node want to leave chord network, send values to the new responsible node.
%
handle_call({leave, Node}, _From, State) ->
    ToList = dict:to_list(State#dict.values),
    [gen_server:call({backend,Node}, {put, Key, Value})
    || {_,{Key,Value}} <- ToList],
    {reply, ok, new_state(State)};

%
% Status, returns the current state (values)
%
handle_call({status}, _From, State) ->
    Values = State#dict.values,
    Size = dict:size(Values),
    Fmt = "#values: ~p~n",
    Params = [Size],
    {reply, {Fmt, Params}, State};

handle_call({status_full}, _From, State) ->
    Values = State#dict.values,
    Size = dict:size(Values),
    Fmt = 
"#values: ~p
verbose: ~p
values: ~p
",
    Params = [Size, State#dict.verbose, Values],
    {reply, {Fmt, Params}, State};

%
% Split the current values between this node and 
% the joining node.
%
handle_call({join}, _From, State) ->
    Dict = State#dict.values,
    NewDict = dict:filter(fun(_,{Key, Value}) ->
                Dest = gen_server:call(?NETWORK, {lookup,Key}),
                case Dest == node() of
                    false ->
                        gen_server:call({?BACKEND,Dest}, {put,Key,Value}),
                        visual:visual_element(Key,Value,Dest,[]),
                        % TODO: Delete element from dict
                        % TODO: Visualize delete element from node
                        false;
                    true  -> 
                        true
                end
                end, Dict),
    NewState = State#dict{values=NewDict},
    {reply, ok, NewState}.

handle_cast(_Msg, State) ->
    {noreply, State}.

terminate(_Reason,_State) ->
    io:format("Terminating dict backend~n").


handle_info(Info, _State) ->
    io:format("Info message received: ~w~n",[Info]).

code_change(_OldVsn, _State, _Extra) ->
    undefined.

% % % % % % % % % % % 
%  State functions
%
new_state(State) ->
    State#dict{values=dict:new()}.

add_value(Key, Value, State) ->
    Dict = State#dict.values,
    NewDict = dict:store(hash:hash(Key), {Key,Value}, Dict),
    State#dict{values=NewDict}.

get_value(Key, State) ->
    Values = State#dict.values,
    dict:find(hash:hash(Key), Values).
